package com.coder520.sync_learning.demo;

import sun.net.dns.ResolverConfiguration;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeoutException;

import static java.lang.Thread.currentThread;

public class Booleanlock implements Lock{
    private Thread currentThread;

    private boolean locked=false;

    private final List<Thread> blockedList=new ArrayList<>();

    @Override
    public void lock() throws InterruptedException  {
        synchronized (this){//同步代码块
            while (locked){//如果当前锁已经被某个线程获得，则该线程将加入到阻塞的队列当中，
                // 并且使当前线程wait释放对this monitor的所有权
                blockedList.add(currentThread);
                this.wait();
            }

            blockedList.remove(currentThread);//如果当前锁没有被其他线程获得，则这个线程将尝试从阻塞的队列当中删除自己
            this.locked=true;
            this.currentThread=currentThread;//记录获取锁的线程
        }
    }

    @Override
    public void lock(long mills) throws InterruptedException, TimeoutException {
        synchronized (this){
            if (mills<=0){//如果时间长度不合法，那么直接使用默认lock方法
                this.lock();
            }else{
                long remainingMills=mills;
                long endMills=currentTimeMills()+remainingMills;
                while (locked){
                    if (remainingMills<=0){//如果不合法，那么意味着当前的线程被其他线程唤醒或者在指定的wait时间到了之后还没有获得锁
                        //这种情况抛出时间超时的一场即可
                        throw new TimeoutException("时间超时了"+mills);
                    }
                    if (!blockedList.contains(currentThread())){
                       blockedList.add(currentThread());
                    }

                    this.wait(remainingMills);//等待的毫秒数最开始，是由其他线程传入的，在多次wait的过程中
                    remainingMills=endMills-currentTimeMills();//重新计算时间
                }

                blockedList.remove(currentThread());//获得这个锁，并且从locked当中进行删除，修改状态为true
                this.locked=true;
                this.currentThread=currentThread();
            }
        }
    }

    private long currentTimeMills() {
        return 1l;
    }

    /**
     *
     */
    @Override
    public void unlock() {
        synchronized (this){
            if(currentThread==currentThread()){
                this.locked=false;
                Optional.of(currentThread().getName()+"release the lock").ifPresent(System.out::println);
                this.notifyAll();
            }

        }
    }


    @Override
    public List<Thread> getBlockedThread() {
        return Collections.unmodifiableList(blockedList);
    }
}
